﻿using HAF.Dispatcher;
using HAF.Dispatcher.Enum;
using HAF.Dispatcher.Impl;
using HAF.Dispatcher.WorkItem;
using HAF.LogUtility;
using HAF.LogUtility.Assistantor;
using HAF.LogUtility.Enum;
using HAF.LogUtility.Model;
using HAF.NetUtility;
using HAF.NetUtility.Assistantor;
using Iptv.ResourceTransfer.Helper;
using Iptv.ResourceTransfer.Model;
using Newtonsoft.Json.Linq;
using RDS.Core;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;

namespace Iptv.ResourceTransfer
{
    /// <summary>
    ///  文件迁移工作项
    /// </summary>
    public class TransferWorkItem : PluginWorkItem, IPluginRegistable
    {
        const string _defLogName = "TransferMonitor";
        /// <summary>
        /// 当前运行站点的配置
        /// </summary>
        private TransferConfig _runConfig;

        #region 插件接口实现
        /// <summary>
        /// 自注册函数
        /// </summary>
        /// <param name="id">工作项编号</param>
        /// <param name="objTask">工作任务对象</param>
        /// <returns></returns>
        public bool Regist(string id, object objTask)
        {
            LogOutName = _defLogName;
            #region 入口参数校验
            if (string.IsNullOrEmpty(id))
            {
                WriteDebugMessageExt(_defLogName, "金沙引擎：方法{0}数据解析错误：{1}", System.Reflection.MethodBase.GetCurrentMethod().Name, "参数ID为空");
                return false;
            }
            if (objTask == null)
            {
                WriteDebugMessageExt(_defLogName, "金沙引擎：方法{0}数据解析错误：{1}", System.Reflection.MethodBase.GetCurrentMethod().Name, "参数obj为空");
                return false;
            }
            #endregion 入口参数校验
            try
            {
                string taskJson = JsonAssistant.Serialize(objTask);
                List<TransferResourceInfo> runTasks = new List<TransferResourceInfo>();
                Type tmpType = objTask.GetType();
                if (objTask is JArray)
                {
                    WriteLine(_defLogName);
                    WriteDebugMessage("进行对象类型{0}转换 {1}", tmpType.Name, taskJson);
                    runTasks = (objTask as JArray).ToObject<List<TransferResourceInfo>>();
                }
                else
                {
                    WriteWarnMessage("对象类型{0}不符合预期 {1}", tmpType.Name, taskJson);
                    runTasks = JsonAssistant.Deserialize<List<TransferResourceInfo>>(taskJson);
                }
                var downJob = new TransferWorkItem()
                {
                    ID = int.Parse(TimeHelper.GetTimeStamp()),
                    TaskID = id, //Guid.NewGuid().ToString("N"),
                    Name = string.Concat("ResTransfer", id),
                    Priority = 5,
                    Model = EnumItemModel.Multi,
                    RedoTimes = 2,
                    WorkID = _defLogName,
                    WorkJson = taskJson,
                    AllowRemoteExec = false,
                    WriteConsoleMessageEvent = RuntimeAdapter.ShowConsol,
                    WorkItems = runTasks,
                    RunLogLevel = HAF.LogUtility.Enum.EnumLogLevel.All
                };
                Dispatcher.GetInstance().RegistTaskItem(downJob);

                //UpdateTopTaskState(id, 1);

                //RuntimeControler.Tasks.Add(id, downJob);
                WriteDebugMessageExt(_defLogName, "金沙引擎：创建{0}工作项完成，资源迁移请求已加入执行队列", id);
                return true;
            }
            catch (Exception ex)
            {
                EndTopTask(TaskID, -1);
                WriteDebugMessageExt(_defLogName, "金沙引擎：方法{0}发生异常：{1}", System.Reflection.MethodBase.GetCurrentMethod().Name, ex.ToString());
                return false;
            }
        }
        #endregion 插件接口实现

        //获取本地配置文件 每次执行的时候读取，实现热配置
        private void RefreshConfig()
        {
            _runConfig = RefreshPluginConfig<TransferConfig>("transferConfig.json");
        }

        /// <summary>
        /// 执行工作项
        /// </summary>
        public override void ExecItem()
        {
            base.ExecItem();

            ReportMessageEvent = PushLog;
            //更新任务状态为启动中
            UpdateTopTaskState(TaskID, 2);
            RefreshConfig();
            this.Statu = EnumRunItemStatu.Exec;
            if (WorkItems != null && WorkItems is List<TransferResourceInfo>)
            {
                var reqTransferTask = WorkItems as List<TransferResourceInfo>;
                if (reqTransferTask != null && reqTransferTask.Count > 0)
                {
                    foreach (var item in reqTransferTask)
                    {
                        WriteDebugMessageExt(item.CorrelateID, "来源地址 {0} 目的地址 {1}", item.ResLocalFullPath, item.ResDestFullPath);
                        var cpConfig = _runConfig.Transfer.Find(t => t.Tag == item.Tag);
                        if (cpConfig != null)
                        {
                            InitNetDisk(cpConfig, item.CorrelateID);
                            //更新界面展示任务基本信息
                            UpdateTopTaskInfo(item.CorrelateID, item.Tag, cpConfig.Name);
                            //判断源文件是否过期，过期的直接删除，不进行迁移
                            if (CheckFileable(cpConfig, item.ResLocalFullPath, item.CorrelateID))
                            {
                                WriteWarnMessageExt(item.CorrelateID, "文件失效，被判定为过期文件，将被自动删除");
                                if (File.Exists(item.ResLocalFullPath))
                                {
                                    File.Delete(item.ResLocalFullPath);
                                }
                                else
                                {
                                    WriteDebugMessageExt(item.CorrelateID, "未检索到文件{0}", item.ResLocalFullPath);
                                }

                                OutMessage.ID = item.CorrelateID;
                                OutMessage.Code = 200;
                                OutMessage.Message = "文件处理成功";

                                EndTopTask(TaskID, 5);
                                TaskNotify(OutMessage, cpConfig.RemoteEngineUrl);
                            }
                            else
                            {
                                ShowDiskInfo(item.CorrelateID);
                                StartTransferFile(item.ResLocalFullPath, item.ResDestFullPath, item.CorrelateID, cpConfig.RemoteEngineUrl);
                            }
                        }
                        else
                        {
                            WriteErrMessageExt(item.CorrelateID, "未找到标签为{0}的可用配置", item.Tag);
                            EndTopTask(TaskID, -1);
                        }
                    }

                }
            }
            else
            {
                WriteErrMessage("任务工作项数据为空{0}", WorkJson);
                EndTopTask(TaskID, 5);
            }
        }

        /// <summary>
        /// 检查文件可删除性
        /// </summary>
        /// <param name="cpConfig">CP配置</param>
        /// <param name="srcFilePath">源文件</param>
        /// <param name="logTag"></param>
        /// <returns></returns>
        private bool CheckFileable(LoadConfig cpConfig, string srcFilePath, string logTag)
        {
            bool rtnValue = false;
            if (cpConfig.AllowDeleteExpireFile)
            {
                int findTime = cpConfig.FileExpireTime;
                DateTime tmpTime = DateTime.Now.AddDays(-findTime);
                //获取文件地址中时间数据
                DateTime fileTime = ParseDateTime(srcFilePath, logTag);
                WriteWarnMessageExt(logTag, "检查当前文件{0}是否可以删除 配置过期时间 {1} 文件提取时间 {2}", srcFilePath, tmpTime, fileTime);
                rtnValue = tmpTime > fileTime;
            }
            return rtnValue;
        }

        private DateTime ParseDateTime(string tmpFilepath, string logTag)
        {
            DateTime rtnDate = DateTime.MaxValue;

            string yearStr = Regex.Match(tmpFilepath, "\\d{6}").Value;
            if (!string.IsNullOrEmpty(yearStr))
            {
                int iDay = tmpFilepath.IndexOf(yearStr) + 6;
                string dateStr = tmpFilepath.Substring(iDay, 3).Remove(0, 1);
                string tmpDateStr = string.Concat(yearStr.Substring(0, 4), "-", yearStr.Substring(4, 2), "-", dateStr);
                WriteDebugMessageExt(logTag, "从{0}中提取到日期数据为 {1}", tmpFilepath, tmpDateStr);

                DateTime.TryParse(tmpDateStr, out rtnDate);
            }
            
            return rtnDate;
        } 

        /// <summary>
        /// 执行文件迁移
        /// </summary>
        /// <param name="srcFilePath">源文件全路径</param>
        /// <param name="destFilePath">目的文件全路径</param>
        /// <param name="logTag">输出日志名称</param>
        /// <param name="postUrl">回执地址</param>
        private void StartTransferFile(string srcFilePath, string destFilePath, string logTag, string postUrl)
        {
            OutMessage.Code = -1;
            if (File.Exists(srcFilePath))
            {
                destFilePath.CreateFolder();
                //string destPath = Path.GetDirectoryName(destFilePath);
                //if (!Directory.Exists(destPath))
                //{
                //    WriteDebugMessageExt(logTag, "目的目录{0}不存在，自动创建该目录", destPath);
                //    Directory.CreateDirectory(destPath);
                //}
                ShowFileInfo(srcFilePath, logTag);
                OutMessage.ID = logTag;
                if (FileAssistantor.FileMove(srcFilePath, destFilePath, logTag))
                {
                    OutMessage.Code = 200;
                    OutMessage.Message = "文件迁移成功";

                    EndTopTask(TaskID, 5);
                    //this.Statu = EnumRunItemStatu.End;
                    TaskNotify(OutMessage, postUrl);
                    return;
                }

                OutMessage.Message = string.Format("文件{0}迁移失败", srcFilePath);
            }
            else
            {
                OutMessage.Message = string.Format("待迁移文件{0}不存在", srcFilePath);
            }

            EndTopTask(TaskID, -1);
            this.Statu = EnumRunItemStatu.Error;
        }

        #region NetDisk
        /// <summary>
        /// 网盘初始化加载
        /// </summary>
        /// <param name="diskCfg">网盘参数</param>
        /// <param name="logTag">日志名称</param>
        private void InitNetDisk(LoadConfig diskCfg, string logTag)
        {
            if (!string.IsNullOrEmpty(diskCfg.DestNetDiskConfig))
            {
                WriteDebugMessageExt(logTag, "当前CP网络盘符参数为{0}", diskCfg.DestNetDiskConfig);
                string[] NetDisKConfig = diskCfg.DestNetDiskConfig.Split(',');
                if (NetDisKConfig.Length > 0)
                {
                    bool isReady = false;
                    var _netDiskKey = NetDisKConfig[2];
                    //磁盘信息缓存判定 如果已经存在则不用进行盘符挂载
                    if (RuntimeAdapter.NetDisks != null && RuntimeAdapter.NetDisks.Count > 0)
                    {
                        WriteDebugMessage(RuntimeAdapter.NetDisks.Keys.ToString());
                        if (RuntimeAdapter.NetDisks.ContainsKey(NetDisKConfig[2]))
                        {
                            isReady = RuntimeAdapter.NetDisks[NetDisKConfig[2]];
                        }
                        else
                        {
                            RuntimeAdapter.NetDisks.Add(NetDisKConfig[2], false);
                        }
                    }

                    if (!isReady)
                    {
                        WriteWarnMessageExt(logTag, "缓存中未找到指定盘符，开始创建网络盘连接");
                        CreateNetDirectory(diskCfg.DestNetDiskConfig, logTag);
                    }
                }
            }

        }

        /// <summary>
        /// 创建本地网络盘符映射
        /// </summary>
        /// <param name="diskCfg">网络盘符配置</param>
        /// <param name="logTag">日志输出标签</param>
        /// <returns></returns>
        private bool CreateNetDirectory(string diskCfg, string logTag)
        {
            if (string.IsNullOrEmpty(diskCfg))
            {
                WriteErrMessageExt(logTag, "网络盘符参数配置异常");
                return false;
            }
            WriteDebugMessageExt(logTag, "当前资源网盘配置信息为：{0}", diskCfg);
            string[] NetDisKConfig = diskCfg.Split(',');
            if (NetDisKConfig.Length > 0)
            {
                uint state = 0;

                string tmpDir = NetDisKConfig[3];
                if (!Directory.Exists(tmpDir))
                {
                    WriteDebugMessageExt(logTag, "创建映射盘符{0}", tmpDir);
                    state = NetDiskHelper.WNetAddConnection(NetDisKConfig[0], NetDisKConfig[1], NetDisKConfig[2], tmpDir);
                }
                else
                {
                    WriteDebugMessageExt(logTag, "映射盘符{0}已存在，可以开始读写数据", tmpDir);
                }

                if (state.Equals(0))
                {
                    RuntimeAdapter.NetDisks[NetDisKConfig[2]] = true;
                    return true;
                }
                else if (state.Equals(1219))
                {
                    RuntimeAdapter.NetDisks[NetDisKConfig[2]] = true;
                    WriteErrMessageExt(logTag, "添加网络驱动器出现异常，异常编号为{0}", state);
                    //如果返回值为1219，表示已创建了链接，可不处理
                    //如要解决该报错，需先使用net use查看所有网络链接，然后使用net use \\172.25.8.78\IPC$ /del /y 进行删除
                    //ERROR_ALREADY_ASSIGNED 85 (0x55) The local device name is already in use. 本地设备名已经使用 
                    //ERROR_BAD_PROVIDER 1204 (0x4B4) The specified network provider name is invalid. 网络名无效
                    //ERROR_ALREADY_ASSIGNED 64 目标驱动器号已经被使用 
                    return true;
                }
                else
                {
                    //1312 是账号密码问题
                    WriteErrMessageExt(logTag, "添加网络驱动器错误，错误号：{0}", state.ToString());
                    return false;
                }
            }
            else
            {
                WriteErrMessageExt(logTag, "映射盘符配置信息异常，请联系系统运维人员");
                return false;
            }
        }

        private void ShowDiskInfo(string logTag)
        {
            DriveInfo[] allDisks = DriveInfo.GetDrives();
            foreach (var item in allDisks)
            {
                if (item.IsReady)
                {
                    WriteDebugMessageExt(logTag, "Drive Lable {0}", item.Name);
                    WriteDebugMessageExt(logTag, "File System {0}", item.DriveFormat);
                    WriteDebugMessageExt(logTag, "Drive Type {0}", item.DriveType);
                    WriteDebugMessageExt(logTag, "Drive Serial {0}", item.VolumeLabel);
                    WriteDebugMessageExt(logTag, "Drive Size {0}", FileAssistantor.GetLengthStr(item.TotalSize));
                    WriteDebugMessageExt(logTag, "Drive Free Space {0}", FileAssistantor.GetLengthStr(item.TotalFreeSpace));
                    WriteLine(logTag);
                }
            }
        }

        private void ShowFileInfo(string filepath, string logTag)
        {
            FileInfo file = new FileInfo(filepath);
            WriteDebugMessageExt(logTag, "FileName {0}", file.Name);
            WriteDebugMessageExt(logTag, "FileSize {0}", FileAssistantor.GetLengthStr(file.Length));
        }

        #endregion NetDisk

        /// <summary>
        /// 
        /// </summary>
        /// <param name="cpConfig"></param>
        private void StartDeleteFiles(LoadConfig cpConfig)
        {
            if (cpConfig.AllowDeleteExpireFile)
            {
                int findTime = cpConfig.FileExpireTime;
            }
        }
    }
}
